package com.xingchi.tornado.core.utils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

/**
 * 请求上下文对象
 *
 * @author xiaoya
 * @date 2024/9/26 9:14
 */
@Slf4j
public class RequestUtils {

    /**
     * 获取请求对象
     *
     * @return  请求对象
     */
    public static HttpServletRequest getRequest() {
        ServletRequestAttributes requestAttributes = getRequestAttributes();
        if (requestAttributes == null) {
            throw new IllegalArgumentException("无法获取到request对象");
        }
        return requestAttributes.getRequest();
    }

    /**
     * 获取响应对象
     *
     * @return  响应对象
     */
    public static HttpServletResponse getResponse() {
        ServletRequestAttributes requestAttributes = getRequestAttributes();
        if (requestAttributes == null) {
            throw new IllegalArgumentException("无法获取到response对象");
        }
        return requestAttributes.getResponse();
    }

    private static ServletRequestAttributes getRequestAttributes() {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if (requestAttributes instanceof ServletRequestAttributes) {
            return (ServletRequestAttributes) requestAttributes;
        }
        return null;
    }

    /**
     * 根据请求获取ip地址
     *
     * @return  请求ip
     */
    public static String getIp() {
        HttpServletRequest request = getRequest();
        return IPUtils.getIp(request);
    }

    /**
     * 从请求参数中获取指定的属性封装得到对应的对象中
     *
     * @param clazz     对应的类
     * @return
     */
    public static  <T> T getObj(Class<T> clazz) {
        HttpServletRequest request = getRequest();

        Field[] fields = clazz.getDeclaredFields();
        T result;
        try {
            Constructor<T> declaredConstructor = clazz.getDeclaredConstructor();
            declaredConstructor.setAccessible(true);
            result = declaredConstructor.newInstance();
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            log.info("无法创建对应class实体对象，原因：{}", e.getMessage(), e);
            return null;
        }
        for (Field field : fields) {
            field.setAccessible(true);
            String fieldValue = request.getParameter(field.getName());
            if (fieldValue != null) {
                ReflectionUtils.setField(field, result, fieldValue);
            }
        }

        return result;
    }

    public static <T extends Authentication> T getAuthentication(Class<T> clazz) {

        if (!Authentication.class.isAssignableFrom(clazz)) {
            log.warn("[{}]类没有实现[{}]接口", clazz.getName(), Authentication.class.getName());
            return null;
        }

        return getObj(clazz);
    }

}
